package jparchess.engine;

public class MoveMaker {
	Board board;
	GameLine gameLine;
	
	public int countMakeMoves = 0;
	public int countUnMakeMoves = 0;
	
	
	public void setBoard(Board board) {
		this.board = board;
	}
	
	public void setGameLine(GameLine gameLine) {
		this.gameLine = gameLine;
	}
	
	//
	// move a piece
	public void doMove(Move move) {
		countMakeMoves++;        
		// special moves are en-passant, castling, promotion
	
		// just the plain normal move
		board.square[move.from] = D.EMPTY;
		
		if (move.promotion == 0) {
			try {
				board.square[move.to] = move.piece;
			} catch (ArrayIndexOutOfBoundsException e) {
				e.printStackTrace();
				D.logDebug(move);
				// TODO: handle exception
			}
			
		}
		else {
			board.square[move.to] = move.promotion;	
			switch (move.promotion) { // exchange pawn for higher value piece
				case D.WHITE_QUEEN: board.material -= D.PAWN_VALUE; board.material += D.QUEEN_VALUE; break;
				case D.WHITE_ROOK: board.material -= D.PAWN_VALUE; board.material += D.ROOK_VALUE; break;
				case D.WHITE_BISHOP: board.material -= D.PAWN_VALUE; board.material += D.BISHOP_VALUE; break;
				case D.WHITE_KNIGHT: board.material -= D.PAWN_VALUE; board.material += D.KNIGHT_VALUE; break;
				case D.BLACK_QUEEN: board.material += D.PAWN_VALUE; board.material -= D.QUEEN_VALUE; break;
				case D.BLACK_ROOK: board.material += D.PAWN_VALUE; board.material -= D.ROOK_VALUE; break;
				case D.BLACK_BISHOP: board.material += D.PAWN_VALUE; board.material -= D.BISHOP_VALUE; break;
				case D.BLACK_KNIGHT: board.material += D.PAWN_VALUE; board.material -= D.KNIGHT_VALUE; break;
			}
		}
			
		
		switch (move.captured) {
			case D.WHITE_PAWN: board.material -= D.PAWN_VALUE; break;
			case D.WHITE_KNIGHT: board.material -= D.KNIGHT_VALUE; break;
			case D.WHITE_BISHOP: board.material -= D.BISHOP_VALUE; break;
			case D.WHITE_ROOK: board.material -= D.ROOK_VALUE; break;
			case D.WHITE_QUEEN: board.material -= D.QUEEN_VALUE; break;
			case D.WHITE_KING: board.material -= D.KING_VALUE; break;
			case D.BLACK_PAWN: board.material += D.PAWN_VALUE; break;
			case D.BLACK_KNIGHT: board.material += D.KNIGHT_VALUE; break;
			case D.BLACK_BISHOP: board.material += D.BISHOP_VALUE; break;
			case D.BLACK_ROOK: board.material += D.ROOK_VALUE; break;
			case D.BLACK_QUEEN: board.material += D.QUEEN_VALUE; break;
			case D.BLACK_KING: board.material += D.KING_VALUE; break;			
		}
		
		switch (move.castling) {
			default: // i.e. 0 (no castling)
				break;
			case D.WHITE_CASTLING_00: board.square[D.H1] = D.EMPTY;
									board.square[D.F1] = D.WHITE_ROOK;
									board.whiteCanCastle00 = false;
									board.whiteCanCastle000 = false;
									break;
			case D.WHITE_CASTLING_000: board.square[D.A1] = D.EMPTY;
									 board.square[D.D1] = D.WHITE_ROOK;
									 board.whiteCanCastle00 = false;
									 board.whiteCanCastle000 = false;
								     break;
			case D.BLACK_CASTLING_00: board.square[D.H8] = D.EMPTY;
									board.square[D.F8] = D.BLACK_ROOK;
									board.blackCanCastle00 = false;
									board.blackCanCastle000 = false;
									break;
			case D.BLACK_CASTLING_000: board.square[D.A8] = D.EMPTY;
									 board.square[D.D8] = D.BLACK_ROOK;
									 board.blackCanCastle00 = false;
									 board.blackCanCastle000 = false;
								     break;		
			}
		
		// if en-passant move before, we must empty the corresponding square
		boolean foundEnPMove = false;
		if (board.sideToMove == D.WHITE_TO_MOVE) {
	        if (move.piece == D.WHITE_PAWN && move.to == board.enPassantSquare) board.square[move.to-8] = D.EMPTY;
	        // set new en-passant square on double move from starting line - otherwise -1
	        if (move.piece == D.WHITE_PAWN && move.from >= D.A2 && move.from <= D.H2 && move.to >= D.A4 && move.to <= D.H4) {
	        	board.enPassantSquare = move.to - 8;
	        	foundEnPMove = true;
	        }
	        	
		}
	    else {
	        // if en-passant move before, we must empty the corresponding square
	        if (move.piece == D.BLACK_PAWN && move.to == board.enPassantSquare) board.square[move.to+8] = D.EMPTY;
	        // set new en-passant square on double move from starting line - otherwise -1
	        if (move.piece == D.BLACK_PAWN &&  move.from >= D.A7 && move.from <= D.H7 && move.to >= D.A5 && move.to <= D.H5) {
	        	board.enPassantSquare = move.to + 8;
	        	foundEnPMove = true;
	        }
	        	
	    }
		if (!foundEnPMove) board.enPassantSquare = -11;
  
        // rochade possibilities
        if (move.piece == D.WHITE_KING) {
        	board.whiteCanCastle00 = false;
        	board.whiteCanCastle000 = false;
        }
        if (move.piece == D.BLACK_KING) {
        	board.blackCanCastle00 = false;
        	board.blackCanCastle000 = false;
        }
        if (move.piece == D.WHITE_ROOK) {
        	if (move.from == D.A1) board.whiteCanCastle000 = false;
        	if (move.from == D.H1) board.whiteCanCastle00 = false;
        }
        if (move.piece == D.BLACK_ROOK) {
        	if (move.from == D.A8) board.blackCanCastle000 = false;
        	if (move.from == D.H8) board.blackCanCastle00 = false;
        }

		
		board.sideToMove = !board.sideToMove;
		
        // adjust gameline     
		gameLine.move.add(move);
		gameLine.flagIndex++;
		gameLine.whiteCanCastle00.add(board.whiteCanCastle00);
		gameLine.whiteCanCastle000.add(board.whiteCanCastle000);
		gameLine.blackCanCastle00.add(board.blackCanCastle00);
		gameLine.blackCanCastle000.add(board.blackCanCastle000);
		gameLine.enPassantSquare.add(board.enPassantSquare);
	}

	
	public void undoMove(Move move) { 
		// special gui undo -> new method				
		if (gameLine.flagIndex > 0) { // only undoMove if gameLine has previous record
			countUnMakeMoves++;
			
			if (move == null) {
				move = gameLine.move.get(gameLine.move.size() - 1);		
			}
						
			
			// restore board info status for previous move
			gameLine.move.remove(gameLine.move.size() - 1);
			board.whiteCanCastle00 = gameLine.whiteCanCastle00.get(gameLine.flagIndex-1); // get previous
									 	 gameLine.whiteCanCastle00.remove(gameLine.flagIndex); // remove very last
			board.whiteCanCastle000 = gameLine.whiteCanCastle000.get(gameLine.flagIndex-1);
										 gameLine.whiteCanCastle000.remove(gameLine.flagIndex);
			board.blackCanCastle00 = gameLine.blackCanCastle00.get(gameLine.flagIndex-1);
							 			 gameLine.blackCanCastle00.remove(gameLine.flagIndex);
			board.blackCanCastle000 = gameLine.blackCanCastle000.get(gameLine.flagIndex-1);
								 		 gameLine.blackCanCastle000.remove(gameLine.flagIndex);
			board.enPassantSquare = gameLine.enPassantSquare.get(gameLine.flagIndex-1);
										 gameLine.enPassantSquare.remove(gameLine.flagIndex);
	
			gameLine.flagIndex--;
			
			// special moves are en-passant, castling, promotion
			
			 switch (move.promotion) { // exchange pawn for higher value piece
				case D.WHITE_QUEEN: board.material += D.PAWN_VALUE; board.material -= D.QUEEN_VALUE; break;
				case D.WHITE_ROOK: board.material += D.PAWN_VALUE; board.material -= D.ROOK_VALUE; break;
				case D.WHITE_BISHOP: board.material += D.PAWN_VALUE; board.material -= D.BISHOP_VALUE; break;
				case D.WHITE_KNIGHT: board.material += D.PAWN_VALUE; board.material -= D.KNIGHT_VALUE; break;
				case D.BLACK_QUEEN: board.material -= D.PAWN_VALUE; board.material += D.QUEEN_VALUE; break;
				case D.BLACK_ROOK: board.material -= D.PAWN_VALUE; board.material += D.ROOK_VALUE; break;
				case D.BLACK_BISHOP: board.material -= D.PAWN_VALUE; board.material += D.BISHOP_VALUE; break;
				case D.BLACK_KNIGHT: board.material -= D.PAWN_VALUE; board.material += D.KNIGHT_VALUE; break;
			}
										 
			// just the plain normal move		
			board.square[move.to] = move.captured; // EMPTY if no piece captured
			board.square[move.from] = move.piece;
			
			switch (move.captured) {
				case D.WHITE_PAWN: board.material += D.PAWN_VALUE; break;
				case D.WHITE_KNIGHT: board.material += D.KNIGHT_VALUE; break;
				case D.WHITE_BISHOP: board.material += D.BISHOP_VALUE; break;
				case D.WHITE_ROOK: board.material += D.ROOK_VALUE; break;
				case D.WHITE_QUEEN: board.material += D.QUEEN_VALUE; break;
				case D.WHITE_KING: board.material += D.KING_VALUE; break;
				case D.BLACK_PAWN: board.material -= D.PAWN_VALUE; break;
				case D.BLACK_KNIGHT: board.material -= D.KNIGHT_VALUE; break;
				case D.BLACK_BISHOP: board.material -= D.BISHOP_VALUE; break;
				case D.BLACK_ROOK: board.material -= D.ROOK_VALUE; break;
				case D.BLACK_QUEEN: board.material -= D.QUEEN_VALUE; break;
				case D.BLACK_KING: board.material -= D.KING_VALUE; break;			
			}
	
			switch (move.castling) {
				default: // i.e. 0 (no castling)
					break;
				case D.WHITE_CASTLING_00: board.square[D.H1] = D.WHITE_ROOK;
										board.square[D.F1] = D.EMPTY;
										break;
				case D.WHITE_CASTLING_000: board.square[D.A1] = D.WHITE_ROOK;
										 board.square[D.D1] = D.EMPTY;
									     break;
				case D.BLACK_CASTLING_00: board.square[D.H8] = D.BLACK_ROOK;
										board.square[D.F8] = D.EMPTY;
										break;
				case D.BLACK_CASTLING_000: board.square[D.A8] = D.BLACK_ROOK;
										 board.square[D.D8] = D.EMPTY;
									     break;		
			}
			
			// en passant moves - undo
			if (move.piece == D.WHITE_PAWN && move.to == board.enPassantSquare) {
				board.square[move.to] = D.EMPTY;
				board.square[move.to-8] = D.BLACK_PAWN; // restore captured en-passant pawn
			}
			if (move.piece == D.BLACK_PAWN && move.to == board.enPassantSquare) {
				board.square[move.to] = D.EMPTY;
				board.square[move.to+8] = D.WHITE_PAWN; // restore captured en-passant pawn
			}
					
			
			board.sideToMove = !board.sideToMove;
		}
		else return;
	}

}
